#ifndef SS_CALCULATOR_IF_H
#define SS_CALCULATOR_IF_H

#include <vector>

#include "SSBasicCalculationPage.h"
#include "SSHoldingPeriodInterest.h"
#include "SSHoldingPeriodResult.h"
#include "SSSingleCalendar.h"
#include "SSSingleCashflow.h"
#include "SSSingleInterestRate.h"
#include "SSSingleRawBondFundamentalInfo.h"

using std::vector;

namespace ssCalculator {

class SSCalculator;

class SSCalculatorIF {
 public:
  static SSCalculatorIF* instance();
  static void destory();

  // set data
  void setBondFundamentalInfo(
      const std::vector<SSSingleRawBondFundamentalInfo>& all_info);
  void addBondFundamentalInfo(
      const std::vector<SSSingleRawBondFundamentalInfo>& all_info);
  void setInterestRate(const std::vector<SSSingleInterestRate>& all_rates);
  void addInterestRate(const std::vector<SSSingleInterestRate>& all_rates);
  void setCalendar(const std::vector<SSSingleCalendar>& all_calendars);

  // date manipulation
  string dateAdvance(const std::string& market, const std::string& date_str,
                     int period_num, const std::string& period_unit,
                     const std::string& convention);

  // simple calculation
  double accruedAmount(const std::string& bond_Key,
                       const std::string& settlementDate) const;

  double dirtyPriceToCleanPrice(const std::string& bond_Key,
                                const std::string& settlementDate,
                                double dirtyPrice) const;
  double ytmToCleanPrice(const std::string& bond_Key,
                         const std::string& settlementDate, double ytm) const;
  double marketSpreadToCleanPrice(const std::string& bond_Key,
                                  const std::string& settlementDate,
                                  double marketSpread) const;
  double ytcToCleanPrice(const std::string& bond_Key,
                         const std::string& settlementDate, double ytc) const;
  double ytpToCleanPrice(const std::string& bond_Key,
                         const std::string& settlementDate, double ytp) const;

  double cleanPriceToDirtyPrice(const std::string& bond_Key,
                                const std::string& settlementDate,
                                double cleanPrice) const;
  double cleanPriceToYTM(const std::string& bond_Key,
                         const std::string& settlementDate,
                         double cleanPrice) const;
  double cleanPriceToMarketSpread(const std::string& bond_Key,
                                  const std::string& settlementDate,
                                  double cleanPrice) const;
  double cleanPriceToYTC(const std::string& bond_Key,
                         const std::string& settlementDate,
                         double cleanPrice) const;
  double cleanPriceToYTP(const std::string& bond_Key,
                         const std::string& settlementDate,
                         double cleanPrice) const;

  double notional(const std::string& bond_Key, const std::string& date) const;

  // cashflows
  std::vector<SSSingleCashflow> cashflowsTable(
      const std::string& bond_Key, const std::string& settlementDate) const;

  // basic calculation page
  bool isFRNBond(const std::string& bond_Key) const;
  bool isOptionEmbedded(const std::string& bond_Key,
                        const std::string& settlementDate) const;
  bool isYTCAvailable(const std::string& bond_Key,
                      const std::string& settlementDate) const;
  bool isYTPAvailable(const std::string& bond_Key,
                      const std::string& settlementDate) const;
  bool isListed(const std::string& bond_Key, const std::string& today) const;
  double prevailingRate(const std::string& bond_Key,
                        const std::string& settlementDate) const;

  SSBasicCalculationPage basicPageInitialize(
      const std::string& bond_Key, const std::string& settlementDate) const;
  SSBasicCalculationPage setCouponRateSpread(const std::string& bond_Key,
                                             const std::string& settlementDate,
                                             double couponRateSpread,
                                             double indexRate) const;
  SSBasicCalculationPage setIndexRate(const std::string& bond_Key,
                                      const std::string& settlementDate,
                                      double couponRateSpread,
                                      double indexRate) const;
  SSBasicCalculationPage clickPrevailingRate(const std::string& bond_Key,
                                             const std::string& settlementDate,
                                             double couponRateSpread) const;

  SSBasicCalculationPage cleanPriceToAll(const std::string& bond_Key,
                                         const std::string& settlementDate,
                                         double couponRateSpread,
                                         double indexRate,
                                         double cleanPrice) const;
  SSBasicCalculationPage dirtyPriceToAll(const std::string& bond_Key,
                                         const std::string& settlementDate,
                                         double couponRateSpread,
                                         double indexRate,
                                         double dirtyPrice) const;
  SSBasicCalculationPage ytmToAll(const std::string& bond_Key,
                                  const std::string& settlementDate,
                                  double couponRateSpread, double indexRate,
                                  double ytm) const;
  SSBasicCalculationPage marketSpreadToAll(const std::string& bond_Key,
                                           const std::string& settlementDate,
                                           double couponRateSpread,
                                           double indexRate,
                                           double marketSpread) const;
  SSBasicCalculationPage ytcToAll(const std::string& bond_Key,
                                  const std::string& settlementDate,
                                  double couponRateSpread, double indexRate,
                                  double ytc) const;
  SSBasicCalculationPage ytpToAll(const std::string& bond_Key,
                                  const std::string& settlementDate,
                                  double couponRateSpread, double indexRate,
                                  double ytp) const;

  // rebate mode
  SSBasicCalculationPage rebateToAll(const std::string& bond_Key,
                                     const std::string& settlementDate,
                                     double couponRateSpread, double indexRate,
                                     double quotedYTM, double rebate) const;
  SSBasicCalculationPage rebateCleanPriceToAll(
      const std::string& bond_Key, const std::string& settlementDate,
      double couponRateSpread, double indexRate, double quotedCleanPrice,
      double rebate) const;
  SSBasicCalculationPage rebateDirtyPriceToAll(
      const std::string& bond_Key, const std::string& settlementDate,
      double couponRateSpread, double indexRate, double quotedDirtyPrice,
      double rebate) const;
  SSBasicCalculationPage rebateMarketSpreadToAll(
      const std::string& bond_Key, const std::string& settlementDate,
      double couponRateSpread, double indexRate, double quotedMarketSpread,
      double rebate) const;
  SSBasicCalculationPage rebateYTCToAll(const std::string& bond_Key,
                                        const std::string& settlementDate,
                                        double couponRateSpread,
                                        double indexRate, double quotedYTC,
                                        double rebate) const;
  SSBasicCalculationPage rebateYTPToAll(const std::string& bond_Key,
                                        const std::string& settlementDate,
                                        double couponRateSpread,
                                        double indexRate, double quotedYTP,
                                        double rebate) const;

  // holding period yield page
  // trade condition --> basic calculation page

  // holding condition
  std::vector<SSHoldingPeriodInterest> holdingPeriodInterests(
      const std::string& startDate, const std::string& endDate,
      const std::string& indexID, double spread, int fixingPeriodNumber,
      const std::string& fixingPeriodUnit, const std::string& simpleCompound,
      const std::string& interestBasis, int preceeds, double notional) const;
  double holdingCost(const std::vector<SSHoldingPeriodInterest>&) const;
  // result
  SSHoldingPeriodResult holdingPeriodResult(
      const std::string& bond_Key, const std::string& startDate,
      const std::string& endDate, const std::string& today, double notional,
      double startCleanPrice, double startAccruedInterest,
      double startFrontDeskCommission, double startBackStageCommission,
      double endCleanPrice, double endAccruedInterest,
      double endFrontDeskCommission, double endBackStageCommission,
      double interestTax, double businessTax, double holdingCost,
      bool buyThenSell, int payHoldingCost) const;

  // Implied Repo Rate
  double impliedRepoRate(const std::string& bond_Key,
                         const std::string& tradeDate,
                         const std::string& settlementDate, double futurePrice,
                         double convertFactor, double dirtyPrice) const;
  double futurePriceByDPAndIRR(const std::string& bond_Key,
                               const std::string& tradeDate,
                               const std::string& settlementDate,
                               double convertFactor, double dirtyPrice,
                               double irr) const;
  double dirtyPriceByFPAndIRR(const std::string& bond_Key,
                              const std::string& tradeDate,
                              const std::string& settlementDate,
                              double convertFactor, double futurePrice,
                              double irr) const;

  // bond valuation
  SSBasicCalculationPage qbBondValuation(
      const std::string& bond_key, const std::string& settlementDate,
      double ytm, const map<string, double>& qbYieldCurve,
      double upwardParallelShift = 0);

  // exceptions
  string exceptions() const;

 private:
  SSCalculatorIF();
  virtual ~SSCalculatorIF();
  static SSCalculatorIF* instance_;
  SSCalculator* impl_;
};

}  // namespace ssCalculator
#endif
